package com.koron.common.core.business.workflow.templates;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.koron.bean.query.Page;
import com.koron.bean.workflow.DefineParam;
import com.koron.common.core.business.workflow.bean.param.BaseParam;
import com.koron.common.core.business.workflow.bean.param.ListParam;
import com.koron.common.core.business.workflow.bean.param.StartParam;
import com.koron.common.core.business.workflow.bean.param.SubmitParam;
import com.koron.common.core.business.workflow.bean.po.SysWorkflow;
import com.koron.common.core.business.workflow.bean.properties.WorkFlowConfigProperties;
import com.koron.common.core.business.workflow.bean.result.FlowList;
import com.koron.common.core.business.workflow.util.HttpUtil;
import com.koron.common.core.business.workflow.util.SecretUtil;
import com.koron.common.core.util.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @author jzp
 * @since 2021/3/31 9:32
 */
@Slf4j
public class WorkFlowTemplates {

    private static final Supplier<String> START_URL = makeUrl("/process/start.htm");

    private static final Supplier<String> SUBMIT_URL = makeUrl("/process/submit.htm");

    private static final Supplier<String> LIST_URL = makeUrl("/process/list.htm");

    private static final Supplier<String> VIEW_URL = makeUrl("/process/view.htm");

    private static final Supplier<String> MOBILE_VIEW_URL = makeUrl("/mobile/approvalView.htm");

    private static final Supplier<String> MOBILE_HISTORY_URL = makeUrl("/mobile/historyView.htm");

    private static final Supplier<String> HISTORY_URL = makeUrl("/process/history.htm");

    private static final Supplier<String> DEFINE_URL = makeUrl("/process/define.htm");

    private static final Supplier<String> END_PROCESS_URL = makeUrl("/process/endProcess.htm");

    private static final Supplier<String> DELETE_PROCESS_URL = makeUrl("/process/deleteProcess.htm");

    private static final Supplier<String> RUN_TASK_CANDIDATE_INFO = makeUrl("/process/runTaskCandidateInfo.htm");

    private static final Supplier<String> LIST_USER_TASK_STATISTICS = makeUrl("/process/listUserTaskStatistics.htm");

    private static Supplier<String> makeUrl(String str) {
        return () -> SpringUtils.getBean(WorkFlowConfigProperties.class).getUrl() + str;
    }

    public static String parseTaskId(String response) {
        JSONObject resultObject = JSONObject.parseObject(response);
        if (resultObject.getInteger("code") == -1) {
            throw new IllegalArgumentException("工作流异常：" + resultObject.getString("description"));
        }
        JSONArray jsonArray = resultObject.getJSONObject("data").getJSONArray("tasks");
        if (jsonArray.size() != 0) {
            return jsonArray.getJSONObject(0).getString("taskId");
        }
        return null;
    }

    /**
     * [
     * processInstanceId,
     * curName,
     * curCode,
     * curCandidatesName,
     * taskId,
     * curNodeUserId,
     * curNodeUserName
     * ]
     *
     * @param response
     * @return
     */
    public static SysWorkflow parseSysWorkflow(String response) {
        JSONObject resultObject = JSONObject.parseObject(response);
        log.info("流程响应：{}", response);
        if (resultObject.getInteger("code") == -1) {
            throw new IllegalArgumentException("工作流异常：" + resultObject.getString("description"));
        }
        SysWorkflow sysWorkflow = new SysWorkflow();
        JSONObject data = resultObject.getJSONObject("data");

        // 设置当前流程信息和上一节点信息
        String processInstanceId = data.getString("processInstanceId");
        String preNodeCode = data.getString("preNodeCode");
        String preNodeName = data.getString("preNodeName");
        String curNodeCandidatesName = data.getString("candidatesName");
        sysWorkflow.setProcessInstanceId(processInstanceId);
        sysWorkflow.setPreNodeCode(preNodeCode);
        sysWorkflow.setPreNodeName(preNodeName);
        sysWorkflow.setCurNodeCandidatesName(curNodeCandidatesName);

        // 设置当前节点信息
        JSONArray curNodes = data.getJSONArray("curNodes");
        StringBuilder curNodeName = new StringBuilder();
        StringBuilder curNodeCode = new StringBuilder();
        String nodeDelimit = ";";

        // 判断curNodeCode是否相同，相同则断言为会审（所以会审和并行不能同时存在）
        long code = IntStream.range(0, curNodes.size()).mapToObj(i -> curNodes.getJSONObject(i).getString("code")).distinct().count();
        int length = code != curNodes.size() ? 1 : curNodes.size(); // 如果存在重复数据(会审)，则大小为1； 不存在（并行），则>1

        for (int i = 0; i < length; i++) {
            JSONObject curNode = curNodes.getJSONObject(i);
            if (i == length - 1) {
                nodeDelimit = "";
            }
            curNodeName.append(curNode.getString("name")).append(nodeDelimit);
            curNodeCode.append(curNode.getString("code")).append(nodeDelimit);
        }
        sysWorkflow.setCurNodeName(curNodeName.toString());
        sysWorkflow.setCurNodeCode(curNodeCode.toString());

        /*
         * 解析task信息
         *
         * 并行人员使用,分割（默认）
         * 会审人员使用&分割
         * 多个节点之间不同人员（并行分支）使用;分割
         */
        String taskDelimit = length > 1 ? ";" : "&";
        JSONArray tasks = data.getJSONArray("tasks");
        StringBuilder taskId = new StringBuilder();
        StringBuilder curNodeUserId = new StringBuilder();
        StringBuilder curNodeUserName = new StringBuilder();
        for (int i = 0; i < tasks.size(); i++) {
            JSONObject curTask = tasks.getJSONObject(i);
            if (i == tasks.size() - 1) {
                taskDelimit = "";
            }
            taskId.append(curTask.getString("taskId")).append(taskDelimit);
            curNodeUserId.append(curTask.getString("user")).append(taskDelimit);
            curNodeUserName.append(curTask.getString("userName")).append(taskDelimit);
        }
        sysWorkflow.setTaskId(taskId.toString());
        sysWorkflow.setCurNodeUserId(Objects.equals(curNodeUserId.toString(), "") ? null : curNodeUserId.toString());
        sysWorkflow.setCurNodeUserName(Objects.equals(curNodeUserName.toString(), "") ? null : curNodeUserName.toString());
        return sysWorkflow;
    }

    public static HashMap<String, Object> base(String appCode, String setCode, String processCode, String operator) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("secret", SecretUtil.getSecret(appCode));
        map.put("setCode", setCode);
        map.put("processCode", processCode);
        map.put("operator", operator);
        return map;
    }
    public static HashMap<String, Object> base(BaseParam baseParam) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("secret", baseParam.getSecret());
        map.put("setCode", baseParam.getSetCode());
        map.put("processCode", baseParam.getProcessCode());
        return map;
    }

    public static HashMap<String, Object> base(BaseParam baseParam, String operator) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("secret", baseParam.getSecret());
        map.put("setCode", baseParam.getSetCode());
        map.put("processCode", baseParam.getProcessCode());
        map.put("operator", operator);
        return map;
    }

    private static HashMap<String, String> baseString(BaseParam baseParam) {
        HashMap<String, String> map = new HashMap<>();
        map.put("secret", baseParam.getSecret());
        if (baseParam.getSetCode() != null) {
            map.put("setCode", baseParam.getSetCode());
        }
        if (baseParam.getProcessCode() != null) {
            map.put("processCode", baseParam.getProcessCode());
        }
        return map;
    }

    public static HashMap<String, String> baseString(String appCode, String setCode, String processCode, String operator) {
        HashMap<String, String> map = new HashMap<>();
        map.put("secret", SecretUtil.getSecret(appCode));
        map.put("setCode", setCode);
        map.put("processCode", processCode);
        map.put("operator", operator);
        return map;
    }

    public static HashMap<String, String> baseString(BaseParam baseParam, String operator) {
        HashMap<String, String> map = baseString(baseParam);
        map.put("operator", operator);
        return map;
    }

    // 启用（空formVariables启用）
    public static String start(String appCode, String setCode, String processCode, String billId, String operator, String title) {
        HashMap<String, Object> base = base(appCode, setCode, processCode, operator);
        base.put("billId", billId);
        base.put("formVariables", new HashMap<>());
        base.put("title", title);
        log.info("流程启动，URL:{}，参数：{}", START_URL.get(), base);
        return HttpUtil.sendPost2(START_URL.get(), base);
    }

    // 启用（formVariables启用）
    public static String start(BaseParam baseParam, String billId, String operator, Map<String, String> formVariables, String title) {
        HashMap<String, Object> base = base(baseParam, operator);
        base.put("billId", billId);
        base.put("formVariables", formVariables);
        base.put("title", title);
        log.info("流程启动，URL:{}，参数：{}", START_URL.get(), base);
        return HttpUtil.sendPost2(START_URL.get(), base);
    }

    // 启用（通用启用）
    public static String start(StartParam startParam) {
        log.info("流程启动，URL:{}，参数：{}", START_URL.get(), JSON.toJSONString(startParam));
        return HttpUtil.sendPost(START_URL.get(), JSON.toJSONString(startParam));
    }

    // 提交
    public static String submit(String appCode, String setCode, String processCode, String billId, String operator, String taskId, String comment) {
        HashMap<String, Object> base = base(appCode, setCode, processCode, operator);
        base.put("billId", billId);
        base.put("formVariables", new HashMap<>());
        base.put("taskId", taskId);
        base.put("operation", 32);
        base.put("comment", comment);
        log.info("流程提交，URL:{}，参数：{}", SUBMIT_URL.get(), base);
        return HttpUtil.sendPost2(SUBMIT_URL.get(), base);
    }

    // 提交
    public static String submit(BaseParam baseParam, String billId, String operator, String taskId, String comment) {
        HashMap<String, Object> base = base(baseParam, operator);
        base.put("billId", billId);
        base.put("formVariables", new HashMap<>());
        base.put("taskId", taskId);
        base.put("operation", 32);
        base.put("comment", comment);
        log.info("流程提交，URL:{}，参数：{}", SUBMIT_URL.get(), base);
        return HttpUtil.sendPost2(SUBMIT_URL.get(), base);
    }

    // 提交
    public static String submit(BaseParam baseParam, String billId, String operator, String taskId, String comment, Map<String, String> formVariables) {
        HashMap<String, Object> base = base(baseParam, operator);
        base.put("billId", billId);
        base.put("formVariables", formVariables);
        base.put("taskId", taskId);
        base.put("operation", 32);
        base.put("comment", comment);
        log.info("流程提交，URL:{}，参数：{}", SUBMIT_URL.get(), base);
        return HttpUtil.sendPost2(SUBMIT_URL.get(), base);
    }

    // 提交
    public static String submit(SubmitParam submitParam) {
        log.info("流程提交，URL:{}，参数：{}", SUBMIT_URL.get(), JSON.toJSONString(submitParam));
        return HttpUtil.sendPost(SUBMIT_URL.get(), JSON.toJSONString(submitParam));
    }

    // 列出当前用户的审核数据
    public static String list(String appCode, String setCode, String processCode, String operator) {
        HashMap<String, String> base = baseString(appCode, setCode, processCode, operator);
        base.put("type", "2");
        log.info("流程列表，URL:{}，参数：{}", LIST_URL.get(), base);
        return HttpUtil.sendGet(LIST_URL.get(), base);
    }

    /**
     * 列出当前用户的审核数据
     *
     * @param listParam::type 类型
     *                        1我发起的
     *                        2我待审的（未办理、可认领、可沟通）
     *                        3参与的(我发起、我已办理、我已沟通)
     *                        4我已沟通的
     *                        5我已办的（包含我发起和我已经办，不含待审）
     */
    public static String list(ListParam listParam) {
        HashMap<String, String> base = baseString(listParam.getBaseParam(), listParam.getOperator());
        base.put("type", listParam.getType().toString());
        base.put("page", listParam.getPage() + "");
        base.put("pageCount", listParam.getPageCount() + "");
        if (!StringUtils.isEmpty(listParam.getStartDate())) {
            base.put("startDate", listParam.getStartDate());
        }
        if (!StringUtils.isEmpty(listParam.getEndDate())) {
            base.put("endDate", listParam.getEndDate());
        }
        if (!StringUtils.isEmpty(listParam.getTitle())) {
            base.put("title", listParam.getTitle());
        }
        if (listParam.getStatus() != null) {
            base.put("status", listParam.getStatus().toString());
        }
        log.info("流程列表，URL:{}，参数：{}", LIST_URL.get(), base);
        log.info("流程列表请求参数，URL:{}，参数：{}", LIST_URL.get(), JSONObject.toJSONString(listParam));
        return HttpUtil.sendGet(LIST_URL.get(), base);
    }

    // 获取工作流界面
    public static String view(BaseParam baseParam, String operator, String billId, String processInstanceId, String variable) {
        HashMap<String, String> base = baseString(baseParam, operator);
        base.put("billId", billId);
        base.put("processInstanceId", processInstanceId);
        if (variable != null) {
            base.put("variable", variable);
        }
        log.info("获取工作流界面，URL:{}，参数：{}", VIEW_URL.get(), base);
        return HttpUtil.sendGet(VIEW_URL.get(), base);
    }

    // 获取初始工作流界面，启动的时候获取工作流界面
    public static String view(BaseParam baseParam, String operator, String variable) {
        HashMap<String, String> base = baseString(baseParam, operator);
        if (variable != null) {
            base.put("variable", variable);
        }
        log.info("获取工作流界面，URL:{}，参数：{}", VIEW_URL.get(), base);
        return HttpUtil.sendGet(VIEW_URL.get(), base);
    }

    // 获取移动端工作流界面
    public static String viewMobile(BaseParam baseParam, String operator, String billId, String processInstanceId, String taskId) {
        HashMap<String, String> base = baseString(baseParam, operator);
        base.put("billId", billId);
        base.put("processInstanceId", processInstanceId);
        base.put("taskId", taskId);
        log.info("获取移动端工作流界面，URL:{}，参数：{}", MOBILE_VIEW_URL.get(), base);
        return HttpUtil.sendGet(MOBILE_VIEW_URL.get(), base);
    }

    // 获取移动端工作流界面
    public static String viewMobile(BaseParam baseParam, String operator) {
        HashMap<String, String> base = baseString(baseParam, operator);
        log.info("获取移动端工作流界面，URL:{}，参数：{}", MOBILE_VIEW_URL.get(), base);
        return HttpUtil.sendGet(MOBILE_VIEW_URL.get(), base);
    }

    // 启动后获取taskId
    public static SysWorkflow executeStart(BaseParam baseParam, String billId, String operator, Map<String, String> formVariables, String dataCode, String dataTitle) {
        if (dataTitle == null) {
            dataTitle = "业务单号：" + dataCode;
        }
        String response = start(baseParam, billId, operator, formVariables, dataTitle);
        return parseSysWorkflow(response);
    }

    // 启动后获取taskId
    public static SysWorkflow executeStart(StartParam startParam) {
        String response = start(startParam);
        return parseSysWorkflow(response);
    }

    // 提交后获取taskId
    public static SysWorkflow executeSubmit(BaseParam baseParam, String billId, String operator, String taskId, String comment, Map<String, String> formVariables) {
        String response = submit(baseParam, billId, operator, taskId, comment, formVariables);
        return parseSysWorkflow(response);
    }

    // 提交后获取taskId
    public static SysWorkflow executeSubmit(SubmitParam submitParam) {
        String response = submit(submitParam);
        return parseSysWorkflow(response);
    }

    // 列出当前用户的所有Flow
    public static Page<FlowList> getBills(ListParam listParam) {
        String response = list(listParam);
        JSONObject resultObject = JSONObject.parseObject(response);
        JSONArray data = resultObject.getJSONArray("data");
        if (data == null) {
            return listParam;
        }
        List<FlowList> flowLists = IntStream.range(0, data.size()).mapToObj(i -> data.getObject(i, FlowList.class)).collect(Collectors.toList());
        listParam.setRecords(flowLists);
        listParam.setTotal(resultObject.getInteger("totalCount"));
        return listParam;
    }

    // 获取移动端工作流历史轨迹
    public static String historyMobile(BaseParam baseParam, String billId, String processInstanceId) {
        HashMap<String, String> base = baseString(baseParam);
        base.put("billId", billId);
        base.put("processInstanceId", processInstanceId);
        log.info("获取工作流历史轨迹，URL:{}，参数：{}", HISTORY_URL.get(), base);
        return HttpUtil.sendGet(HISTORY_URL.get(), base);
    }

    // 工作流模板节点信息
    public static String define(DefineParam defineParam) {
        BaseParam baseParam = new BaseParam();
        baseParam.setAppCode(defineParam.getProcessCode());
        baseParam.setSetCode(defineParam.getSetCode());
        baseParam.setProcessCode(defineParam.getProcessCode());
        return define(baseParam, defineParam.getTaskCode());
    }

    public static String define(BaseParam baseParam, String taskCode) {
        HashMap<String, String> base = baseString(baseParam);
        if (!StringUtils.isEmpty(taskCode)) {
            base.put("taskCode", taskCode);
        }
        log.info("获取工作流模板节点，URL:{}，参数：{}", DEFINE_URL.get(), base);
        return HttpUtil.sendGet(DEFINE_URL.get(), base);
    }

    public static String end(BaseParam baseParam, String processInstanceId, String operator) {
        HashMap<String, Object> base = base(baseParam, operator);
        base.put("processInstanceId", processInstanceId);
        log.info("流程结束，URL:{}，参数：{}", END_PROCESS_URL.get(), base);
        return HttpUtil.sendPost2(END_PROCESS_URL.get(), base);
    }

    public static String delete(BaseParam baseParam, String processInstanceId) {
        HashMap<String, Object> base = base(baseParam);
        base.put("processInstanceId", processInstanceId);
        log.info("流程删除，URL:{}，参数：{}", DELETE_PROCESS_URL.get(), base);
        return HttpUtil.sendPost2(DELETE_PROCESS_URL.get(), base);
    }

    //  获取运行中的节点处理人信息
    public static String runTaskCandidateInfo(BaseParam baseParam, String processInstanceId) {
        HashMap<String, Object> base = base(baseParam);
        base.put("processInstanceId", processInstanceId);
        log.info("获取运行中的节点处理人信息，URL:{}，参数：{}", RUN_TASK_CANDIDATE_INFO.get(), base);
        return HttpUtil.sendPost2(RUN_TASK_CANDIDATE_INFO.get(), base);
    }

    // 获取人员待办任务数量汇总
    public static String listUserTaskStatistics(BaseParam baseParam, String startDate, String endDate, List<String> accountList) {
        HashMap<String, String> base = new HashMap<>();
        base.put("secret", baseParam.getSecret());
        if (baseParam.getSetCode()!=null) {
            base.put("setCode", baseParam.getSetCode());
        }
        if (!StringUtils.isEmpty(startDate)) {
            base.put("startDate", startDate);
        }
        if (!StringUtils.isEmpty(endDate)) {
            base.put("endDate", endDate);
        }
        if (!CollectionUtils.isEmpty(accountList)) {
            base.put("accountList", String.join(",", accountList));
        }
        log.info("获取人员待办任务数量汇总，URL:{}，参数：{}", LIST_USER_TASK_STATISTICS.get(), base);
        return HttpUtil.sendGet(LIST_USER_TASK_STATISTICS.get(), base);
    }
}
